#! /bin/sh
#
# %CopyrightBegin%
#
# SPDX-License-Identifier: Apache-2.0
#
# Copyright Ericsson AB 2002-2025. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# %CopyrightEnd%
#

USE_AUTOCONF_VERSION=2.72

autoconf_aux_dirs="./erts/autoconf ./lib/common_test/test_server"

install_sh_master="./make/autoconf/install-sh"
config_guess_master="./make/autoconf/config.guess"
config_sub_master="./make/autoconf/config.sub"

# Global configuration variables
#
if [ -z "$ONLY_ERTS" ]; then
    AUTOCONF_SUBDIRS="lib lib/* lib/common_test/test_server"
fi
AUTOCONF_SUBDIRS="$AUTOCONF_SUBDIRS make erts"

# `bootstrap_apps' should include application that are built, or
# partly built in one of the bootstrap phases. Applications that
# only get some static includes copied into the bootstrap directory
# should not be included.
bootstrap_apps="erts lib/asn1 lib/compiler lib/erl_interface lib/kernel lib/jinterface lib/parsetools lib/sasl lib/snmp lib/stdlib lib/syntax_tools lib/wx"

# We will quote a bit more than needed, but the important thing is that
# all that needs quoting will be quoted...
DONT_QUOTE="A-Za-z0-9~/=_+-"

# Utility functions
usage ()
{
    echo "Available commands:"
    echo "    setup [-a|-s|-t] [<configure parameters>] - does autoconf, configure and boot"
    echo "    all [-a|-s|-t] <dir> - does autoconf, configure, boot, release"
    echo "    autoconf - (re)build the configure scripts"
    echo "    configure [<configure parameters>] - does the actual configuration"
    echo "    boot [-a|-s|-t] - bootstraps and builds the system (after configure)"
    echo "    release <target_dir> - creates a small release to <target_dir>"
    echo "    release [-a|-s|-t] <target_dir> - creates full release to <target_dir>"
    echo "    tests <dir> - Build testsuites to <dir>"
    echo "    check [--help|...] - Perform various build checks. See --help for more info"
    echo "                         and options."
    echo ""
    echo "-a builds all applications"
    echo "-s builds a small system (default)"
    echo "-t builds a tiny system"
    echo ""
    echo "These are for cleaning up an open source distribution"
    echo "with prebuilt files, so that it resembles the clean developers"
    echo "codebase:"
    echo "    remove_prebuilt_files - create a minimal source tree"
    echo "    save_bootstrap - recreate primary bootstrap"
    echo ""
    echo "Special targets for setting up the build environment:"
    echo "    download_ex_doc             - download the correct ExDoc version from github"
    echo "    update_ex_doc [--no-commit] - update and maybe commit new ex_doc version"
    echo ""
    echo "Special targets for setting up gdb tooling:"
    echo "    download_gdb_tools             - download the correct gdb tooling version from github"
    echo "    update_gdb_tools [--no-commit] - update and maybe commit new gdb tooling version"
    echo ""
    echo "Special targets for Windows(tm) build:"
    echo "    debuginfo_win32 <dir> - adds debug emulator and pdb files to <dir>"
    echo "    installer_win32 <dir> - creates a windows installer from <dir>" 
    echo ""
    echo "Before trying to build on windows, consider the following option"
    echo "    env_win32 [<arch>] - echo environment settings for win32 with visual C++, use with eval"
    echo "                         The optional <arch> can be x64 for 64bit Windows"
    echo "                         or x86 for 32bit Windows"
    echo "    env_win64 - echo environment settings for win32 with visual C++, use with eval"
    echo "                Note that env_win32 x64 gives the same result, Windows 64bit"
    echo ""
    echo "update_primary [--no-commit]      - build and maybe commit a new primary bootstrap"
    echo "update_preloaded [--no-commit]    - build and maybe commit the preloaded modules"
    echo "update_deprecations [--no-commit] - build and maybe commit deprecations"
    echo "update_configure [--no-commit]    - build and maybe commit configure scripts"
}

hide_vars ()
{
    script=
    for var in "$@"; do
	if [ "X$var" != "X" ]; then
	    script="$script test \"X\$$var\" = \"X\" || hidden_$var=\$$var; unset $var;"
	fi
    done
    if [ "X$script" != "X" ]; then
	eval "$script"
    fi
    unset script
}

restore_vars ()
{
    script=
    for var in "$@"; do
	if [ "X$var" != "X" ]; then
	    script="$script unset $var; test \"X\$hidden_$var\" = \"X\" || { $var=\$hidden_$var; export $var; } ; unset hidden_$var;"
	fi
    done
    if [ "X$script" != "X" ]; then
	eval "$script"
    fi
    unset script
}


check_erltop ()
{
        ERLTOP_FORCED=false
	if [ "X$ERL_TOP" = "X" ]; then
		if [ -f ./otp_build -a -f ./make/autoconf/config.guess ]; then
		    ERLTOP_FORCED=true
		    ERL_TOP=`pwd`
		    export ERL_TOP
		else
		    echo "The environment variable ERL_TOP must be set." >&2
		    exit 1
		fi
	fi
}

target_contains ()
{
	Y=`echo $TARGET | sed "s,$1,,g"`
	[ X"$Y" != X"$TARGET" ]
	return $?
} 

determine_version_controller ()
{
    version_controller=none

    # The current directory is now $ERL_TOP. Find out whether
    # this directory is a git repository.

    if { git rev-parse --git-dir; } 2>/dev/null >/dev/null; then
	version_controller=git
    fi
}
# Execution of the different options

# Special static config flags for certain platforms are set here  
set_config_flags ()
{
	#
	# NOTE! Do not add special flags here without a *very good*
	#       reason. We normally do not want "./otp_build configure"
	#       and "./configure" to produce different results.
	#       However, in the Windows case this does not matter, since
	#       the only supported way to build on Windows is using
	#       otp_build.
	#
	# * Extra flags to pass to configure are placed in `CONFIG_FLAGS'.
	# * The command line is no longer added to `CONFIG_FLAGS' by
	#   `set_config_flags'. It is instead passed directly to
	#   `run_configure', or added to `CONFIG_FLAGS' at some other
	#   place.
	# * `CONFIG_FLAGS' may contain flags when `set_config_flags' is
	#   called. These flags should survive the call to `set_config_flags'
	#   (in the cross compilation case the whole command line as well as
	#   the cross configuration have been moved here). 

	if target_contains win32; then
		if [ "$CONFIG_SUBTYPE" = "win64" ]; then
			build_type=local-x86_64-pc-windows
			host_type=local-x86_64-pc-windows
			target_type=local-x86_64-pc-windows
		elif [ "$CONFIG_SUBTYPE" = "arm64" ]; then
			build_type=local-aarch64-pc-windows
			host_type=local-aarch64-pc-windows
			target_type=local-aarch64-pc-windows
		elif [ "$CONFIG_SUBTYPE" = "x64_arm64" ]; then
			build_type=local-x86_64-pc-windows
			host_type=local-aarch64-pc-windows
			target_type=local-aarch64-pc-windows
	    else
			build_type=local-x86-pc-windows
			host_type=local-x86-pc-windows
			target_type=local-x86-pc-windows
	    fi
	    CONFIG_FLAGS="--build=$build_type --host=$host_type --target=$target_type $CONFIG_FLAGS" 
	fi
	    

	if [ "x$OVERRIDE_CONFIG_CACHE" = "x" ]; then
	    CONFIG_FLAGS="$CONFIG_FLAGS --cache-file=/dev/null"
	else
	   CONFIG_FLAGS="$CONFIG_FLAGS --cache-file=$OVERRIDE_CONFIG_CACHE" 
	fi

	env_to_config_flags $erl_build_tool_vars

	export CONFIG_FLAGS;
}

NL="\
"

do_update_configure ()		
{
    get_do_commit $1

    export AUTOCONF_VERSION="$USE_AUTOCONF_VERSION"
    ac_ver_blob=`autoconf --version`
    if [ $? -ne 0 ]; then
	echo "ERROR: Failed to check autoconf version! You need to have autoconf of version $USE_AUTOCONF_VERSION in path." 1>&2
	exit 1
    fi
    ac_ver=`echo $ac_ver_blob | sed "s|[^0-9]*\([0-9][^ \t\n]*\).*|\1|"`
    case $ac_ver in
	$USE_AUTOCONF_VERSION)
	    ;;
	*)
	    echo "ERROR: autoconf of version $ac_ver found in path! You need to have autoconf of version $USE_AUTOCONF_VERSION in path." 1>&2
	    exit 1;;
    esac
    
    out_files=

    install_sh=`basename $install_sh_master`
    config_guess=`basename $config_guess_master`
    config_sub=`basename $config_sub_master`

    for dir in $autoconf_aux_dirs; do
	$install_sh_master -d "$dir"
	$install_sh_master -t "$dir" "$install_sh_master"
	out_files="$out_files $dir/$install_sh"
	$install_sh_master -t "$dir" "$config_guess_master"
	out_files="$out_files $dir/$config_guess"
	$install_sh_master -t "$dir" "$config_sub_master"
	out_files="$out_files $dir/$config_sub"
    done
	
    hide_vars OVERRIDE_TARGET TARGET
    TARGET=$BUILDSYS
    export TARGET

    for d in $AUTOCONF_SUBDIRS; do
	file="$d/configure.ac"
	[ -f "$file" ] || continue
	echo ""
	[ ! -d "$d/autom4te.cache" ] || {
	    echo "=== cleaning $d/autom4te.cache"
	    rm -f "$d"/autom4te.cache/*
	}
	[ ! -f "$d/configure" ] || {
	    echo "=== cleaning $d/configure"
	    rm -f "$d"/configure
	}

	echo "=== running autoconf in $d"
	( cd "$d" && autoconf -B "$ERL_TOP/make/autoconf") || exit 1
	out_files="$out_files $d/configure"
	chdr=`cat "$file" | sed -n "s|.*\(AC_CONFIG_HEADER\).*|\1|p"`
	[ "$chdr" = "AC_CONFIG_HEADER" ] || continue
	echo "=== running autoheader in $d"
	( cd "$d" && autoheader -B "$ERL_TOP/make/autoconf") || exit 1
	out_files="$out_files $d/config.h.in"
    done

    echo ""
    echo "=== creating ./configure"
    bootstrap_lib_apps=`echo $bootstrap_apps | sed "s|erts||g"`
    cat "$ERL_TOP/configure.src" \
	| sed "s|@BOOTSTRAP_LIB_APP_DIRS@|$bootstrap_lib_apps|g" \
	      > "$ERL_TOP/configure"
    chmod +x "$ERL_TOP/configure"
    out_files="./configure $out_files"

    restore_vars OVERRIDE_TARGET TARGET

    if [ $do_commit != true ]; then
	echo "Updated: $out_files"
    else
	git add $out_files
	if [ $? -ne 0 ]; then
	    echo "Failed to stage files for commit" 1>&2
	    exit 1
	fi
	git diff --cached --quiet
	if [ $? -eq 0 ]; then
	    echo "No files changed, so nothing to commit."
	else
            git commit --no-verify -m 'Update configure scripts'
	    if [ $? -ne 0 ]; then
		echo "Failed to commit files" 1>&2
		exit 1
	    fi
	    echo "Updated configure scripts!"
	fi
    fi
}

run_configure ()
{
    cdir="$ERL_TOP"
    [ -z "$ONLY_ERTS" ] || {
	cdir="$ERL_TOP/erts"
	CONFIG_FLAGS="$CONFIG_FLAGS --no-recursion"
    }

    echo "$cdir/configure $CONFIG_FLAGS" ${1+"$@"}
    (cd "$cdir" && $config_eval ./configure $CONFIG_FLAGS ${1+"$@"}) || exit 1
}

env_to_config_flags ()
{
    for env_var in "$@"; do
	script="echo $env_var=\$$env_var; unset $env_var >/dev/null 2>&1"
	env_arg=`eval $script`
	case $env_arg in
	    "$env_var=")
		;;
	    *[!$DONT_QUOTE]*)
		config_eval=eval
		new_arg=`echo "X$env_arg" | sed "s|^X||;s|\([^$DONT_QUOTE]\)|\\\\\\\\\1|g"`
		CONFIG_FLAGS="$CONFIG_FLAGS $new_arg";;
	    *)
		CONFIG_FLAGS="$CONFIG_FLAGS $env_arg";;
	esac
	eval unset $env_var
    done
}

try_cross_configure ()
{
    cross_configure=no
    host_value=
    build_value=

    # Get `erl_xcomp_vars'
    . "$ERL_TOP/xcomp/erl-xcomp-vars.sh" || exit 1

    for arg in ${1+"$@"}; do
	case "$arg" in
	    --host=*)
		host_value=`echo $x | sed "s|^--host=\(.*\)|\1|"`;;
	    --build=*)
		build_value=`echo $x | sed "s|^--build=\(.*\)|\1|"`;;
	    --xcomp-conf=*)
		cross_configure=yes;;
	    *)
		;;
	esac
    done

    test $cross_configure = yes || {

	test "X$host_value" = "X" || {

	    test "X$build_value" != "X" || build_value="$BUILDSYS"

	    build_sys=`"$ERL_TOP/make/autoconf/config.sub" "$build_value"` || exit 1
	    host_sys=`"$ERL_TOP/make/autoconf/config.sub" "$host_value"` || exit 1

	    
	    test "$host_sys" = "$build_sys" || cross_configure=yes
	}
    }

    test $cross_configure = yes || return 1

    # cross configure...
    CONFIG_FLAGS=

    env_to_config_flags $erl_build_tool_vars $erl_xcomp_vars

    for arg in ${1+"$@"}; do
	case "$arg" in
	    --host=*)
		host_value=`echo $x | sed "s|^--host=\(.*\)|\1|"`;;
	    --build=*)
		build_value=`echo $x | sed "s|^--build=\(.*\)|\1|"`;;
	    --xcomp-conf=*)
		# tilde expansion is not handled by the `configure' script,
		# but we do it for this argument. This argument is however not
		# a `configure' argument.
	        xcomp_conf=`echo "X$arg" | sed "s|^X--xcomp-conf=\(.*\)\$|\1|g;s|\([^$DONT_QUOTE]\)|\\\\\\\\\1|g"`
		eval "xcomp_conf=$xcomp_conf"
		test "X$xcomp_conf" != "X" || {
		    echo "$0: Missing xcomp-conf file name"
		    exit 1
		}
		test -f "$xcomp_conf" || {
		    echo "$0: Missing xcomp-conf file: $xcomp_conf"
		    exit 1
		}
		. "$xcomp_conf"
		test $? -eq 0 || {
		    echo "$0: Failed to read xcomp-conf file: $xcomp_conf"
		    exit 1
		}
		test "X$erl_xcomp_build" = "X" || build_value="$erl_xcomp_build"
		test "X$erl_xcomp_host" = "X" || host_value="$erl_xcomp_host"
		unset erl_xcomp_build
		unset erl_xcomp_host
		CONFIG_FLAGS="$CONFIG_FLAGS $erl_xcomp_configure_flags"
		unset erl_xcomp_configure_flags
		env_to_config_flags $erl_build_tool_vars $erl_xcomp_vars;;
	    *[!$DONT_QUOTE]*)
		config_eval=eval
	        new_arg=`echo "X$arg" | sed "s|^X||;s|\([^$DONT_QUOTE]\)|\\\\\\\\\1|g"`
		CONFIG_FLAGS="$CONFIG_FLAGS $new_arg";;
	    *)
		CONFIG_FLAGS="$CONFIG_FLAGS $arg";;
	esac
    done

    CONFIG_FLAGS="--host=$host_value $CONFIG_FLAGS"
    test "X$build_value" != "Xguess" || build_value="$BUILDSYS"
    test "X$build_value" = "X" || CONFIG_FLAGS="--build=$build_value $CONFIG_FLAGS"

    # Configure build system for boot strap
    cat <<EOF

*
* Configuring the bootstrap build system...
*

EOF

    # hide build tools environment which is for the cross configure
    set_config_flags $CONFIG_FLAGS
    hide_vars CONFIG_FLAGS

    set_config_flags 
    run_configure --enable-bootstrap-only

    # restore the hidden build tools environment for the cross configure
    restore_vars CONFIG_FLAGS

    COMPFIX=""
    cat <<EOF

*
* Configuring the cross host system ($host_value)...
*

EOF
    # We don't pass the command line here since we already have moved it
    # into CONFIG_FLAGS
    run_configure

    return 0
}

maybe_copy_static_cache ()
{
    if [ '!' -z "$OVERRIDE_CONFIG_CACHE_STATIC" ]; then
	if [ '!' -z "$OVERRIDE_CONFIG_CACHE" ]; then
	    echo "Copying static configure cache $OVERRIDE_CONFIG_CACHE_STATIC to $OVERRIDE_CONFIG_CACHE"
	    cp -f "$OVERRIDE_CONFIG_CACHE_STATIC" "$OVERRIDE_CONFIG_CACHE"
	fi
    fi
}

do_configure ()
{
    setup_make

    # Get `erl_build_tool_vars'
    . "$ERL_TOP/erl-build-tool-vars.sh" || exit 1

    maybe_copy_static_cache
    try_cross_configure "$@"
    if [ $cross_configure = no ]; then
	CONFIG_FLAGS=
	set_config_flags "$@"
	run_configure "$@"
    fi
}

echo_setenv ()
{
    case "$DAILY_BUILD_SCRIPT$SHELL" in
	true*)
	    echo "$1=$2";;
	*ash|*ksh|*/sh|*zsh|*ash)
	    echo "$1=\"$2\";export $1$3";;
	*csh)
	    echo "setenv $1 \"$2\"$3";;
    esac
}

echo_env_bootstrap ()
{
    boot_bin=$BOOTSTRAP_ROOT/bootstrap/bin
    
    echo_setenv PATH $boot_bin:$PATH
}

echo_env_erltop ()
{
    if [ X"$ERL_TOP" = X"" -o "$ERLTOP_FORCED" = "true" ]; then
	if [ -f ./otp_build ]; then
	    # Seems to be current directory...
	    echo_setenv ERL_TOP `pwd` ';'
	else
	    echo "You need to either set ERL_TOP first or stand in the same" \ 
		"directory as this script resides in." >&2
	    exit 1
	fi
    fi
}

echo_envinfo ()
{
    case "$SHELL" in
	*csh)
	    return 0
	    ;;
	*)
	    ;;
    esac
    if [ X"$DAILY_BUILD_SCRIPT" = X"true" ]; then
	echo '# Output generated for daily build script only '\
	     '($DAILY_BUILD_SCRIPT=true)'
    else
	echo '# Please note:'
	echo '# The command you are running is supposed to be run'\
	     'using the shells'
	echo '# "eval" builtin, like in:'
	echo '# $ eval `./otp_build env_<something>`'
	echo '# If you see this comment, you probably haven'"'"'t done that.'
    fi
}

#
#  Cygwin build without microsoft visual C++ (dead?)
#
echo_env_mingw32 ()
{
    #echo_envinfo
    if [ X"$SHELL" = X"" ]; then
	echo "You need to export the shell variable first," \
		"for bourne-like shells, type:" >&2
	echo 'export SHELL' >&2
	echo "and for csh-like shells, type:" >&2
	echo 'setenv SHELL $SHELL' >&2
	echo " - then try again." >&2
	exit 1
    fi
    echo_env_erltop
    CCYGPATH=`cygpath c:\\`
    DCYGPATH=`cygpath d:\\`
    P2=`echo :$PATH | \
	sed "s,\",,g;s,:[cC]:,:$CCYGPATH,g;s,:[dD]:,:$DCYGPATH,g;s,^:,,"`
    P3=""
    save_ifs=$IFS
    IFS=:
    for p in $P2; do
	if [ -d "$p" ]; then
	    C1="`(cygpath -d $p 2>/dev/null || cygpath -w $p)`" 2> /dev/null
	    C2=`cygpath "$C1" 2> /dev/null` 2> /dev/null
	else
	    C2=""
	fi
	if [ ! -z "$C2" ]; then
	    if [ -z "$P3" ];then 
		P3="$C2"
	    else 
		P3="$P3:$C2"
	    fi
	fi
    done
    found=false
    for p in $P3; do
	if [ -f "$p/mingw32-gcc.exe" ]; then
	    found=$p
	fi
    done
    found2=false
    for p in $P3; do
	if [ -f "$p/wmc.exe" ]; then
	    found2=$p
	fi
    done
    IFS=$save_ifs
    if [ X"$found" = X"false" ]; then
	echo "Could not find mingw32-gcc in PATH, build with mingw not possible!" >&2
	return
    fi

    if [ X"$found2" = X"false" ]; then
	echo "Could not find wmc.exe in PATH, part of wine for windows, " >&2
	echo "needed for message file compilation: http://wine.sourceforge.net!!" >&2
	return
    fi
    WIN32_WRAPPER_PATH="$ERL_TOP/erts/etc/win32/cygwin_tools/mingw:$ERL_TOP/erts/etc/win32/cygwin_tools"


    echo_setenv OVERRIDE_TARGET win32 ';'
    echo_setenv MINGW_EXE_PATH $found ';'
    echo_setenv WINE_EXE_PATH $found2 ';'
    echo_setenv CC cc.sh ';'
    echo_setenv CXX cc.sh ';'
    echo_setenv AR ar.sh ';'
    echo_setenv RANLIB true ';'
    echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';'
    echo_setenv PATH "$WIN32_WRAPPER_PATH:$P3" ';'
    echo_envinfo
}

# N.B. In Erlang, and the build system, win32 means windows, so we keep
# everything as terget win32, but add the CONFIG_SUBTYPE win64, which can
# be handled by configure, setting WINDOWS_64BIT in headers and such
echo_env_cygwin ()
{
    X64=$1
    #echo_envinfo
    if [ X"$SHELL" = X"" ]; then
	echo "You need to export the shell variable first," \
		"for bourne-like shells, type:" >&2
	echo 'export SHELL' >&2
	echo "and for csh-like shells, type:" >&2
	echo 'setenv SHELL $SHELL' >&2
	echo " - then try again." >&2
	exit 1
    fi
    echo_env_erltop
    # Try to cope with paths containing unexpected things like stray 
    # mixed paths (c:/something/bin) and quotes. Only C and D drive
    # handled.
    CCYGPATH=`cygpath c:\\`
    DCYGPATH=`cygpath d:\\`
    P2=`echo :$PATH | \
	sed "s,\",,g;s,:[cC]:,:$CCYGPATH,g;s,:[dD]:,:$DCYGPATH,g;s,^:,,"`
    P3=""
    save_ifs=$IFS
    IFS=:
    for p in $P2; do
	if [ -d "$p" ]; then
	    C1="`(cygpath -d $p 2>/dev/null || cygpath -w $p)`" 2> /dev/null
	    C2=`cygpath "$C1" 2> /dev/null` 2> /dev/null
	else
	    C2=""
	fi
	if [ ! -z "$C2" ]; then
	    if [ -z "$P3" ];then 
		P3="$C2"
	    else 
		P3="$P3:$C2"
	    fi
	fi
    done
    IFS=$save_ifs
    WIN32_WRAPPER_PATH="$ERL_TOP/erts/etc/win32/cygwin_tools/vc:$ERL_TOP/erts/etc/win32/cygwin_tools"

    echo_setenv OVERRIDE_TARGET win32 ';'
    if [ X"$X64" = X"true" ]; then
        echo_setenv CONFIG_SUBTYPE win64 ';'
    fi
    echo_setenv CC cc.sh ';'
    echo_setenv CXX cc.sh ';'
    echo_setenv AR ar.sh ';'
    echo_setenv RANLIB true ';'
    if [ X"$X64" = X"true" ]; then
        if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win64.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';'
    else
        if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win32.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';'
    fi
    echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';'
    echo_setenv PATH "$WIN32_WRAPPER_PATH:$P3" ';'
    echo_envinfo
}

echo_env_msys ()
{
    X64=$1
    #echo_envinfo
    if [ X"$SHELL" = X"" ]; then
	echo "You need to export the shell variable first," \
		"for bourne-like shells, type:" >&2
	echo 'export SHELL' >&2
	echo "and for csh-like shells, type:" >&2
	echo 'setenv SHELL $SHELL' >&2
	echo " - then try again." >&2
	exit 1
    fi
    echo_env_erltop
    # Try to cope with paths containing unexpected things like stray 
    # mixed paths (c:/something/bin) and quotes. Only C and D drive
    # handled.
    P2=`echo :$PATH | \
	sed "s,\",,g;s,:\([a-zA-Z]\):,:/\L\1,g;s,^:,,"`
    P3=""
    save_pwd=`pwd`
    save_ifs=$IFS
    IFS=:
    for p in $P2; do
	if [ -d "$p" ]; then
	    C1=`(cd "$p" && cmd //C "for %i in (".") do @echo %~fsi")`
	    C2=`echo "$C1" | sed 's,^\([a-zA-Z]\):\\\\,/\L\1/,;s,\\\\,/,g'`
	else
	    C2=""
	fi
	if [ ! -z "$C2" ]; then
	    if [ -z "$P3" ];then 
		P3="$C2"
	    else 
		P3="$P3:$C2"
	    fi
	fi
    done
    IFS=$save_ifs
    WIN32_WRAPPER_PATH="$ERL_TOP/erts/etc/win32/msys_tools/vc:$ERL_TOP/erts/etc/win32/msys_tools"

    echo_setenv OVERRIDE_TARGET win32 ';'
    if [ X"$X64" = X"true" ]; then
        echo_setenv CONFIG_SUBTYPE win64 ';'
    fi
    echo_setenv CC cc.sh ';'
    echo_setenv CXX cc.sh ';'
    echo_setenv AR ar.sh ';'
    echo_setenv RANLIB true ';'
    if [ X"$X64" = X"true" ]; then
        if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win64.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';'
    else
        if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win32.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';'
    fi
    echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';'
    echo_setenv PATH "$WIN32_WRAPPER_PATH:$P3" ';'
    echo_envinfo
}

echo_env_wsl ()
{
    ARCH=$1
    #echo_envinfo
    if [ X"$SHELL" = X"" ]; then
	echo "You need to export the shell variable first," \
		"for bourne-like shells, type:" >&2
	echo 'export SHELL' >&2
	echo "and for csh-like shells, type:" >&2
	echo 'setenv SHELL $SHELL' >&2
	echo " - then try again." >&2
	exit 1
    fi
    echo_env_erltop

    WIN32_WRAPPER_PATH="$ERL_TOP/erts/etc/win32/wsl_tools/vc:$ERL_TOP/erts/etc/win32/wsl_tools"

    if [ ! -n "`lookup_prog_in_path cl`" ]; then
        if [ X"$ARCH" = X"x64" ]; then
            setup_win32_cl_env "x64" `wslpath -a -m erts/etc/win32/wsl_tools/SetupWSLcross.bat`
        elif [ X"$ARCH" = X"arm64" ]; then
            setup_win32_cl_env "arm64" `wslpath -a -m erts/etc/win32/wsl_tools/SetupWSLcross.bat`
        elif [ X"$ARCH" = X"x64_arm64" ]; then
            setup_win32_cl_env "x64_arm64" `wslpath -a -m erts/etc/win32/wsl_tools/SetupWSLcross.bat`
        else
            setup_win32_cl_env "x86" `wslpath -a -m erts/etc/win32/wsl_tools/SetupWSLcross.bat`
        fi
    fi
    echo_setenv OVERRIDE_TARGET win32 ';'
    if [ X"$ARCH" = X"x64" ]; then
        echo_setenv CONFIG_SUBTYPE win64 ';'
    elif [ X"$ARCH" = X"arm64" -o X"$ARCH" = X"x64_arm64" ]; then
        echo_setenv CONFIG_SUBTYPE "$ARCH" ';'
    fi
    echo_setenv WSLcross true ';'
    echo_setenv CC cc.sh ';'
    echo_setenv CXX cc.sh ';'
    echo_setenv AR ar.sh ';'
    echo_setenv RANLIB true ';'
    if [ X"$ARCH" = X"x64" ]; then
        if [ -f "$ERL_TOP/make/autoconf/win64.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win64.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64.config.cache" ';'
    elif [ X"$ARCH" = X"arm64" -o X"$ARCH" = X"x64_arm64" ]; then
        if [ -f "$ERL_TOP/make/autoconf/win64-$ARCH.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win64-$ARCH.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win64-$ARCH.config.cache" ';'
    else
        if [ -f "$ERL_TOP/make/autoconf/win32.config.cache.static" ]; then
	    echo_setenv OVERRIDE_CONFIG_CACHE_STATIC  "$ERL_TOP/make/autoconf/win32.config.cache.static" ';'
        fi
        echo_setenv OVERRIDE_CONFIG_CACHE "$ERL_TOP/make/autoconf/win32.config.cache" ';'
    fi
    echo_setenv WIN32_WRAPPER_PATH "$WIN32_WRAPPER_PATH" ';'
    echo_setenv PATH "$WIN32_WRAPPER_PATH:$PATH" ';'
    echo_envinfo
}


setup_win32_cl_env ()
{
    eval `cmd.exe /c $2 $1`
    echo_setenv INCLUDE "$INCLUDE" ';'
    echo_setenv LIB "$LIB" ';'
    echo_setenv LIBPATH "$LIBPATH" ';'
    echo_setenv VCToolsRedistDir "$VCToolsRedistDir" ';'
    echo_setenv WSLENV "$WSLENV:WSLPATH/l:CLASSPATH/l" ';'

    save_ifs=$IFS
    IFS=:
    WSLPATH=""
    for p in $PATH; do
	if [ -d "$p" ]; then
	    case "$p" in
		/mnt/c/*)
		    WSLPATH=$WSLPATH:$p
		    ;;
		*)
		    ;;
	    esac
	fi
    done
    IFS=$save_ifs
    echo_setenv WSLPATH "$WSLPATH" ';'
}

lookup_prog_in_path ()
{
    PROG=$1
    save_ifs=$IFS
    IFS=:
    for p in $PATH; do
	# In cygwin the programs are not always executable and have .exe suffix...
	if [ "X$TARGET" = "Xwin32" ]; then
	    if [ -f $p/$PROG.exe ]; then
		echo $p/$PROG
		break;
	    fi
	else
	    if [ -x $p/$PROG ]; then
		echo $p/$PROG
		break;
	    fi
	fi
    done
    IFS=$save_ifs
}

setup_make ()
{
    if [ -z "$MAKE" ]; then
	case $TARGET in
	    win32)
		MAKE=make;;
	    *)
		if [ -n "`lookup_prog_in_path gmake`" ]; then
		    MAKE=gmake
		else
		    MAKE=make
		fi;;
       esac
    fi
    export MAKE
}

get_do_commit ()
{
    case $version_controller in
	git)
	    if [ "x$1" = "x" ]; then
		do_commit=true
	    elif [ "$1" = "--no-commit" ]; then
		do_commit=false
	    else
		echo "Unknown option '$1'" 1>&2
		exit 1
	    fi;;
	none)
	    do_commit=false;;
    esac
}
  
do_deprecations_git ()
{
    get_do_commit $1
    setup_make

    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET \
        deprecations || exit 1;

    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET \
        primary_bootstrap || exit 1;

    if [ $do_commit = true ]; then
        git add -A bootstrap/lib/stdlib/ebin/otp_internal.beam
        git add -A lib/stdlib/src/otp_internal.erl
        git commit --no-verify -m 'Update deprecations'
        echo ""
        echo "Deprecations updated and committed."
        echo ""
    else
        echo ""
        echo "Deprecations updated. Use the following commands to stage "
        echo "changed files:"
        echo ""
        echo "$ git add bootstrap/lib/stdlib/ebin/otp_internal.beam"
        echo "$ git add lib/stdlib/src/otp_internal.erl"
        echo ""
    fi
}
  
do_primary_git ()
{
    get_do_commit $1
    setup_make
    if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
	do_primary_cross
    else
	$MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET primary_bootstrap || exit 1;
    fi
    if [ $do_commit = true ]; then
	git add -A bootstrap/lib/kernel \
            bootstrap/lib/stdlib \
	    bootstrap/lib/compiler \
	    bootstrap/bin
	find bootstrap -name egen -o -name '*.script' -o \
	    -name '*.app' -o -name '*.appup' |
        xargs git reset HEAD
	git commit --no-verify -m 'Update primary bootstrap'
        git checkout HEAD -- bootstrap
	echo "Primary bootstrap updated and commited."
    else
	echo ""
	echo "Primary bootstrap rebuilt."
	if [ $version_controller = git ]; then
	    echo "Use \"git add bootstrap/...\" to stage changed files."
	fi
	echo ""
    fi
}

do_update_prel_git ()
{
    get_do_commit $1
    setup_make
    (cd "$ERL_TOP/erts/preloaded/src" && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET clean)
    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET preloaded || exit 1
    (cd "$ERL_TOP/erts/preloaded/src" && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET copy)
    if [ $do_commit = true ]; then
	git add -A "$ERL_TOP/erts/preloaded/ebin/*.beam"
	git commit -m 'Update preloaded modules'
	echo "Preloaded updated and commited."
    else
	echo ""
	echo "Preloaded rebuilt."
	if [ $version_controller = git ]; then
	    echo "Use \"git add erts/preloaded/ebin/...\" to stage changed beam files."
	fi
	echo ""
    fi
}

do_boot ()
{
    setup_make

    # Bootstrap if we are cross compiling
    if [ X`$MAKE is_cross_configured` = Xyes ]; then
	TARGET=$BUILDSYS
	$MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT CROSS_COMPILING=no TARGET=$TARGET bootstrap || exit 1
	TARGET=`$MAKE target_configured`
    elif [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
	hide_vars OVERRIDE_TARGET TARGET
	TARGET=$BUILDSYS
	$MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET bootstrap || exit 1

	restore_vars OVERRIDE_TARGET TARGET
    fi

    # Build it (including bootstrap if not cross compiling)
    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET \
        TYPE="$TYPE" FLAVOR="$FLAVOR" \
        all || exit 1
}

do_boot_emu ()
{
    setup_make
    if [ X`$MAKE is_cross_configured` = Xyes ]; then
	TARGET=`$MAKE target_configured`
    fi
    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET \
        TYPE="$TYPE" FLAVOR="$FLAVOR" \
        emulator || exit 1
}

do_release ()
{
    setup_make
    if [ X`$MAKE is_cross_configured` = Xyes ]; then
	TARGET=`$MAKE target_configured`
    fi
    $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET \
        TYPE="$TYPE" FLAVOR="$FLAVOR" \
	RELEASE_ROOT=$1 OTP_STRICT_INSTALL=$OTP_STRICT_INSTALL \
	release || exit 1
}

do_tests ()
{
    setup_make
    if [ X`$MAKE is_cross_configured` = Xyes ]; then
	TARGET=`$MAKE target_configured`
    fi
    if [ X"$1" = X"" ]; then
	$MAKE MAKE="$MAKE" TARGET=$TARGET release_tests || exit 1
    else
	$MAKE MAKE="$MAKE" TARGET=$TARGET TESTSUITE_ROOT=$1 release_tests || exit 1
    fi
}

do_check ()
{
    exec $ERL_TOP/scripts/otp_build_check "$@"
}

do_download_ex_doc ()
{
    SHASUM_FORMAT=

    ## Download ex_doc and place in $ERL_TOP/bin folder
    curl -s -L "$(cat "$ERL_TOP/make/ex_doc_link")" > "$ERL_TOP/bin/ex_doc"
    chmod +x "$ERL_TOP/bin/ex_doc"

    choose_available_shasum     # sets the SHASUM_FORMAT
    check_shasum "ex_doc" "$ERL_TOP/bin" "$ERL_TOP/make"

    echo "Downloaded ex_doc to $ERL_TOP/bin/ex_doc"
}

do_download_gdb_tools ()
{
    set_common_vars

    if [ ! -d "$GDB_TOOLS_INSTALL_PATH" ]
    then
        clone_gdb_tools
    fi

    cwd=$(pwd);

    cd "$GDB_TOOLS_INSTALL_PATH" || exit 1

    CURRENT_GDB_VERSION=$(git log HEAD --oneline --no-abbrev-commit -n1 | cut -d" " -f1)

    if [ "$CURRENT_GDB_VERSION" != "$GDB_TOOLS_VSN" ]; then
        echo "Setting up gdb_tools"
        git fetch gdb_tools > /dev/null || exit 1
        git checkout "$GDB_TOOLS_VSN" > /dev/null || exit 1
    else
        exit 0
    fi

    cd "$cwd" || exit 1
    
    echo "Downloaded gdb-tools for Erlang/OTP $OTP_VERSION"

    exit 0
}

set_common_vars() {
    GDB_TOOLS_INSTALL_PATH="$ERL_TOP/erts/etc/unix/gdb-tools"
    GDB_TOOLS_VSN_PATH="$ERL_TOP/make"
    GDB_REPO=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_link" | grep -v "^//")

    # Version of gdb-tools to download
    GDB_TOOLS_VSN=$(cat "$GDB_TOOLS_VSN_PATH/gdb_tools_vsn" | grep -v "^//")

    # SHASUM_FORMAT has values: sha256sum, sha1sum, shasum
    SHASUM_FORMAT=

    OTP_VERSION=
    set_otp_version
}

clone_gdb_tools ()
{
    echo "Downloading gdb-tools for Erlang/OTP $OTP_VERSION"
    echo "git clone --origin gdb_tools $GDB_REPO $GDB_TOOLS_INSTALL_PATH"
    (git clone --origin gdb_tools "$GDB_REPO" "$GDB_TOOLS_INSTALL_PATH" > /dev/null 2>&1)  || {
        echo "Downloading gdb_tools failed. Please check your source tree, and report this error."
        exit 1
        }
}

clean_file ()
{
    rm -rf "$1"
}

set_otp_version ()
{
    OTP_VERSION=$(cat $ERL_TOP/OTP_VERSION | cut -d. -f1)
    if [ $OTP_VERSION -le 24 ]
    then
        echo "OTP version $OTP_VERSION is too old. Please update to a newer OTP version"
        exit 1
    fi
}

do_update_gdb_tools ()
{
    get_do_commit $1
    set_common_vars

    if [ $do_commit = true ] && test -n "$(git status --porcelain --untracked-files=no)"
    then
        echo "'otp_build update_gdb_tools' will create a commit."
        echo "Git's working directory is not clean."
        echo "Please stash or commit the working directory before proceeding."
        exit 1
    fi


    if grep "rc" "$ERL_TOP/OTP_VERSION" > /dev/null
    then
        if [ -d "$GDB_TOOLS_INSTALL_PATH" ]
        then
            cd "$GDB_TOOLS_INSTALL_PATH" && \
                git fetch $GDB_REPO && \
                GDB_TOOLS_VSN=$(git log gdb_tools/master --oneline --no-abbrev-commit -n1 | cut -d" " -f1) && \
                cat <<EOF > "$ERL_TOP/make/gdb_tools_vsn"
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2024 Ericsson and the Erlang/OTP contributors
$GDB_TOOLS_VSN
EOF
        else
            echo "Please, download gdb_tools invoking the command: \`otp_build download_gdb_tools\`"
            exit 1
        fi
    else
        echo "Please look in repo: $GDB_REPO the commit sha you are interested."
        echo "Copy that commit into $ERL_TOP/make/gdb_tools_vsn and run \`otp_build download_gdb_tools\`"
        exit 1
    fi

    out_files=  # why is this needed. it was needed for elixir

    echo "Successfully updated gdb_tools"
    if [ $do_commit != true ]; then
        echo "Updated: make/gdb_tools_vsn make/jit-reader.c.sha256sum"
    else
        set_common_vars
        git add "$ERL_TOP/make/gdb_tools_vsn" \
                "$GDB_TOOLS_VSN_PATH/jit-reader.c.sha256sum" \
                "$GDB_TOOLS_VSN_PATH/jit-reader.h.sha256sum" > /dev/null
        git commit -m  "Updated gdb_tools version to $GDB_TOOLS_VSN" > /dev/null
    fi
    echo "Run \`otp_build download_gdb_tools\` to complete the installation of the update"
}

choose_available_shasum ()
{
    if command -v sha256sum > /dev/null; then
        SHASUM_FORMAT="sha256sum"
    elif command -v sha1sum > /dev/null; then
        SHASUM_FORMAT="sha1sum"
    elif command -v shasum > /dev/null; then
        # shasum produces the same sha as sha1sum.
        SHASUM_FORMAT="sha1sum"
    else
        echo "Neither sha1sum nor sha256sum nor shasum found" >&2
        exit 1
    fi
}

# $1: expected file,
#     e.g., `jit-reader.c`, `ex_doc`
# $2: path to expeted file,
#     e.g., `$ERL_TOP/bin`, which is where `ex_doc` is found.
#     makes easy to find errors in the path.
# $3: path where shasum lives
#     e.g., `$ERL_TOP/make` in case of sha256sum and sha1sum files.
check_shasum()
{
    case $SHASUM_FORMAT in
        "sha256sum" )
            if ! (cd "$3" && sha256sum -c "$1.$SHASUM_FORMAT" > /dev/null); then
                echo "The sha256sum check of $2/$1 failed!" >&2
                exit 1
            fi;;
        "sha1sum" )
            if ! (cd "$3" && sha1sum -c "$1.$SHASUM_FORMAT" > /dev/null); then
                echo "The sha1sum check of $2/$1 failed!" >&2
                exit 1
            fi;;
        "shasum" )
            if ! (cd "$3" && shasum -a 1 -c "$1.$SHASUM_FORMAT" > /dev/null); then
                echo "The shasum check of $2/$1 failed!" >&2
                exit 1
            fi
    esac
}

## Update make/ex_doc_link, make/ex_doc.sha256sum and make/ex_doc.sha1sum
do_update_ex_doc ()
{
    get_do_commit $1

    OTP_VERSION=$(awk -F. '{ print $1 }' "$ERL_TOP/OTP_VERSION")
    EX_DOC_VSN=$(curl --silent -qI https://github.com/elixir-lang/ex_doc/releases/latest | awk -F '/' '/^location/ {print  substr($NF, 1, length($NF)-1)}')
    if grep "rc" "$ERL_TOP/OTP_VERSION" > /dev/null || curl --silent -Li "https://github.com/elixir-lang/ex_doc/releases/download/${EX_DOC_VSN}/ex_doc_otp_${OTP_VERSION}" > /dev/null; then
        OTP_VERSION="$(($OTP_VERSION-1))"
    fi
    if command -v sha1sum > /dev/null && command -v sha256sum > /dev/null; then
        echo "https://github.com/elixir-lang/ex_doc/releases/download/${EX_DOC_VSN}/ex_doc_otp_${OTP_VERSION}" > "$ERL_TOP/make/ex_doc_link"
        echo "${EX_DOC_VSN}" > "$ERL_TOP/make/ex_doc_vsn"
        curl -sL "https://github.com/elixir-lang/ex_doc/releases/download/${EX_DOC_VSN}/ex-doc-otp-${OTP_VERSION}.sha256sum" | sed 's:ex_doc.*$:../bin/ex_doc:' > "$ERL_TOP/make/ex_doc.sha256sum"
        curl -sL "https://github.com/elixir-lang/ex_doc/releases/download/${EX_DOC_VSN}/ex-doc-otp-${OTP_VERSION}.sha1sum" | sed 's:ex_doc.*$:../bin/ex_doc:' > "$ERL_TOP/make/ex_doc.sha1sum"
        if do_download_ex_doc; then

            out_files=

            ## do_download_ex_doc checked sha1sum, we check sha256sum here to make sure
            ## both are correct.
            if ! (cd "$ERL_TOP/make" && sha256sum --status -c "ex_doc.sha256sum"); then
                echo "The sha256sum check of $ERL_TOP/bin/ex_doc failed!" >&2
                exit 1
            fi
            echo "Successfully updated ex_doc"
            if [ $do_commit != true ]; then
                echo "Updated: make/ex_doc_link make/ex_doc_vsn make/ex_doc_link.sha256sum make/ex_doc_link.sha1sum"
            else
                git add $ERL_TOP/make/ex_doc_link $ERL_TOP/make/ex_doc_vsn  $ERL_TOP/make/ex_doc.sha256sum $ERL_TOP/make/ex_doc.sha1sum
                git commit -m  "Updated ex_doc version to ${EX_DOC_VSN}"
            fi
        fi
    else
        echo "You need to have both sha1sum and sha256sum installed to update ex_doc"
        exit 1
    fi
}

do_debuginfo_win32 ()
{
    setup_make
    (cd erts/emulator && $MAKE MAKE="$MAKE" TARGET=$TARGET debug) || exit 1
    if [ -z "$1" ]; then
       RELDIR="$ERL_TOP/release/$TARGET"
    else
       RELDIR="$1"
    fi
    (cd erts/emulator && $MAKE release RELEASE_ROOT="$RELDIR" MAKE="$MAKE" TARGET=$TARGET TYPE=debug) || exit 1
}

do_installer_win32 ()
{
    setup_make
    installer_dir="$ERL_TOP/erts/etc/win32/nsis"
    (cd $installer_dir; $MAKE MAKE="$MAKE" TARGET=$TARGET TESTROOT=$1 release) || exit 1
}

do_copy_primary_bootstrap ()
{
    if [ "x$1" = "x" ]; then
	echo "Missing bootstrap source top" 1>&2
	exit 1
    fi
    if  [ ! -d $1 ]; then
	echo "Invalid bootstrap source top" 1>&2
	exit 1
    fi
    if [ "x$2" = "x" ]; then
	echo "Missing bootstrap root" 1>&2
	exit 1
    fi
    if  [ ! -d $2 ]; then
	echo "Invalid bootstrap root" 1>&2
	exit 1
    fi

    bootstrap=$2/bootstrap
    bootstrap_src_top=$1
    lib_src=$bootstrap_src_top/lib

    # kernel
    test -d $bootstrap/lib/kernel/ebin || mkdir -p  $bootstrap/lib/kernel/ebin
    test -d $bootstrap/lib/kernel/include || mkdir -p  $bootstrap/lib/kernel/include
    cp -f $lib_src/kernel/ebin/*.beam $bootstrap/lib/kernel/ebin
    cp -f $lib_src/kernel/include/*.hrl $bootstrap/lib/kernel/include

    # stdlib
    test -d $bootstrap/lib/stdlib/ebin || mkdir -p  $bootstrap/lib/stdlib/ebin
    test -d $bootstrap/lib/stdlib/include || mkdir -p  $bootstrap/lib/stdlib/include
    cp -f $lib_src/stdlib/ebin/*.beam $bootstrap/lib/stdlib/ebin
    cp -f $lib_src/stdlib/include/*.hrl $bootstrap/lib/stdlib/include

    # compiler
    test -d $bootstrap/lib/compiler/ebin || mkdir -p  $bootstrap/lib/compiler/ebin
    cp -f $lib_src/compiler/ebin/*.beam $bootstrap/lib/compiler/ebin

    # bootstrap bin
    if [ $bootstrap_src_top != "$ERL_TOP" ]; then
	test -d $bootstrap/bin || mkdir -p  $bootstrap/bin
	cp -f $bootstrap_src_top/bin/* $bootstrap/bin
    fi

}

do_save_bootstrap ()
{
    if [ ! -f "$ERL_TOP/prebuilt.files" ]; then
	echo "This is not a pre-built source distribution" 1>&2
	exit 1
    fi
    if  [ -d "$ERL_TOP/bootstrap/lib" ]; then
	echo "Bootstrap already exist" 1>&2
	exit 1
    fi

    do_copy_primary_bootstrap "$ERL_TOP" "$ERL_TOP"
}

do_remove_prebuilt_files ()
{
    do_save_bootstrap
    for file in "$ERL_TOP"/`cat "$ERL_TOP/prebuilt.files"` ; do
	rm -f $file
    done
}

# main

check_erltop

cd "$ERL_TOP"

determine_version_controller

# Unset ERL_FLAGS and ERL_OTP<OTP Release>_FLAGS during bootstrap to
# prevent potential problems
otp_major_vsn=`cat OTP_VERSION | sed "s|\([0-9]*\).*|\1|"`
erl_otp_flags="ERL_OTP${otp_major_vsn}_FLAGS"
unset ERL_FLAGS
unset ${erl_otp_flags}

# Target first guess, won't necessarily hold, may be changed for 
# certain parameters.
if [ X"$TARGET" = X"" ]; then
	TARGET=`"$ERL_TOP/make/autoconf/config.guess"`
fi
BUILDSYS=$TARGET

case $TARGET in
    *-cygwin)
	if [ X"$BUILD_FOR_CYGWIN" = X"" ]; then
	    if [ X"$OVERRIDE_TARGET" = X"" -a X"$1" != X"env_win32" -a X"$1" != X"env_win64" -a  X"$1" != X"env_mingw32" ];then
		echo "Building for windows, you should do the " \
		    "following first:" >&2
		echo 'eval `./otp_build env_win32`' >&2
		echo 'please note that there are backticks (``) in' \
		    'the command'
		exit 1
	    fi
	fi;;
    *-mingw32)
	if [ X"$OVERRIDE_TARGET" = X"" -a X"$1" != X"env_win32" -a X"$1" != X"env_msys32" -a X"$1" != X"env_msys64"  ];then
	    echo "Building for windows, you should do the " \
		"following first:" >&2
	    echo 'eval `./otp_build env_win32`' >&2
	    echo 'or' >&2
	    echo 'eval `./otp_build env_win32 x64`' >&2
	    echo 'please note that there are backticks (``) in' \
		'the command'
	    exit 1
	fi;;
    *)
        if [ -x /bin/wslpath -a X"$OVERRIDE_TARGET" = X"" \
                -a X"$1" != X"env_win32" -a X"$1" != X"env_msys32" -a X"$1" != X"env_msys64" ]; then
            echo "Building linux binary; if you intended to cross build for win32 (x64) use"  >&2
            echo '   eval `./otp_build env_win32 x64`\n' >&2
        fi
        ;;
esac

if [ ! -z "$OVERRIDE_TARGET" ]; then
    TARGET="$OVERRIDE_TARGET"
fi

# Setting a bootstrap root is inherently very dangerous now that the bootstrap
# is prebuilt, avoid it if not forced by setting FORCE_BOOTSTRAP_ROOT=true!

if [ X"$FORCE_BOOTSTRAP_ROOT" != X"true" ]; then
    BOOTSTRAP_ROOT="$ERL_TOP"
else 
    if [ -z "$BOOTSTRAP_ROOT" ]; then
	BOOTSTRAP_ROOT="$ERL_TOP"
    fi
fi

if [ X"$1" = X"" ]; then 
	usage
	exit 1
fi

if [ X"$2" = X"-a" ]; then
    minus_x_flag=true
    OTP_SMALL_BUILD=
elif [ X"$2" = X"-s" ]; then
    minus_x_flag=true
    OTP_SMALL_BUILD=true
elif [ X"$2" = X"-t" ]; then
    minus_x_flag=true
    OTP_TINY_BUILD=true
else
    minus_x_flag=false
    OTP_SMALL_BUILD=true
fi
export OTP_SMALL_BUILD OTP_TINY_BUILD

TYPE=$TYPE
case "$1" in
 	all)
 		do_configure; 
 		do_boot;
		if [ $minus_x_flag = true ]; then
 		    shift
 		fi;
 		do_release "$2";;
	setup)
		shift;
		if [ $minus_x_flag = true ]; then
		    shift
		fi;
		do_configure "$@";
		do_boot;;
	autoconf)
	    echo ""
	    echo "*** It is not necessary to execute './otp_build autoconf' anymore! ***"
	    echo ""
	    echo "All configure scripts have been committed in the repository and are"
	    echo "therefore always available. If you need to update them, execute"
	    echo "'./otp_build update_configure [--no-commit]'. Ensure that you have"
	    echo "autoconf version $USE_AUTOCONF_VERSION in your PATH before updating the configure"
	    echo "scritps."
	    echo ""
	    echo "The only effect of executing './otp_build autoconf' is printing of this"
	    echo "message."
	    echo ""
	    exit 0;;
	configure)
		shift;
		do_configure "$@";;
	opt)
		do_boot;;
	smp)
		if [ $minus_x_flag = false ]; then
		    TYPE=opt
		fi;
		FLAVOR=$1
		do_boot;;
	update_configure)
	    do_update_configure "$2";;
	update_deprecations)
	        do_deprecations_git "$2";;
	update_primary)
	        do_primary_git "$2";;
	update_preloaded)
	        do_update_prel_git "$2";;
        primary)
	        echo "Primary bootstrap is under version control since R13";
		echo "Use update_primary if you really are";
		echo "updating the primary bootstrap...";;
	boot)
		do_boot;;
        emulator)
	        do_boot_emu;;
	release)
		if [ $minus_x_flag = true ]; then
		    shift
		fi;
		do_release "$2";;
	tests)
		if [ $minus_x_flag = true ]; then
		    shift
		fi;
		do_tests "$2";;
        remove_prebuilt_files)
		do_remove_prebuilt_files;;
        save_bootstrap)
		do_save_bootstrap;;
        copy_primary_bootstrap)
	        do_copy_primary_bootstrap $2 $3;;
        download_gdb_tools)
            do_download_gdb_tools;;
        update_gdb_tools)
            do_update_gdb_tools $2;;
        download_ex_doc)
                do_download_ex_doc;;
        update_ex_doc)
                do_update_ex_doc $2;;
	installer_win32)
		if [ $minus_x_flag = true ]; then
		    shift
		fi;
		do_installer_win32 "$2";;
	debuginfo_win32)
		if [ $minus_x_flag = true ]; then
		    shift
		fi;
		do_debuginfo_win32 "$2";;
	env_win32)
		if [ x"$2" = x"x64" -o x"$2" = x"amd64" ]; then
			ISX64=true
			WSL_ARCH=x64
		elif [ x"$2" = x"arm64" ]; then
			ISX64=false
			WSL_ARCH=arm64
		elif [ x"$2" = x"x64_arm64" ]; then
			ISX64=false
			WSL_ARCH=x64_arm64
		else
			ISX64=false
			WSL_ARCH=x86
		fi
		if [ -x /bin/wslpath ]; then
			echo_env_wsl $WSL_ARCH
		elif [ -x /usr/bin/msys-?.0.dll ]; then
			echo_env_msys $ISX64
		else
			echo_env_cygwin $ISX64
		fi;;
	env_mingw32)
		echo_env_mingw32;;
	env_win64)
		if [ -x /bin/wslpath ]; then
			if [ x"$2" = x"arm64" ]; then
				WSL_ARCH=arm64
			elif [ x"$2" = x"x64_arm64" ]; then
				WSL_ARCH=x64_arm64
			else
				WSL_ARCH=x64
			fi
			echo_env_wsl $WSL_ARCH
		elif [ -x /usr/bin/msys-?.0.dll ]; then
			echo_env_msys true
		else
			echo_env_cygwin true
		fi;;
	env_msys32)
		echo_env_msys;;
	env_msys64)
		echo_env_msys true;;
	env_cross)
		echo_env_cross "$2";;
        env_bootstrap)
	        echo_env_bootstrap;;
	check)
		shift;
		do_check "$@";;
	*)
		usage;;
esac
